/**
 *    本规范定义了一个 API 用于提供脚本化访问鼠标原始移动数据的能力，在鼠标事件中将这些数据锁定到单个元素
 * 对象中去，并从视图中删除游标。这一能力对某些类型应用来说是刚需，特比是第一人称3D应用和3D模型软件
 */

/**
 *    Pointer Lock API 提供给应用一些能力，作为一种输入方法直接描述鼠标运动，不再只能通过鼠标游标定位信息。
 * 一个流行的示例是第一人称3D运动控制，比如3D图形应用游戏：通过鼠标控制玩家视角的旋转和方向；不显示鼠标
 * 游标，并且鼠标运动没有被限制在传统的边界框中，这意味着任何方向的鼠标运动都可以被追踪。
 *    Pointer Lock 与鼠标捕获有关。当鼠标在目标元素上拖动时，捕获会持续抛出事件，并在鼠标按钮释放时
 * 停止。指针锁因持久性而不同，不受屏幕边界的影响，不管鼠标按钮状态如何都会发送事件，隐藏光标，知道用户
 * 调用API或者使用特定手势解锁释放。
 *    Pointer Lock 将捕获处理为单一资源，并与某个元素关联。这与将某个元素提升为全屏的 FullScreen API 相似，
 * Pointer Lock API 选择模仿资源捕获、状态变化以及在释放API上尽可能与 FullScreen API 靠近。
 *    除了鼠标操作指针外其他很多不同控制类型的名称都发生了改变，都受到了影响。
 */

/**
 * pointerlockchange 和 pointerlockerror 事件
 *    这两个事件用于表述指针锁状态变化或者状态变化中产生的错误。
 *    UA 必须通过事件队列来分发这些事件，并在触发对应操作名称的事件时，将指针锁目标对象元素上的
 *  bubbles 属性设为 false。
 */

/**
 * 扩展 Eelment 接口
 *    在 Element 接口上扩展了下面的方法 {
 *      void requestPoinerLock ()
 *    }
 *    请求将指针锁定到一个DOM元素。UA 决定如果指针锁定状态设置时，锁定状态发生变更或者抛出异常，则分别
 * 触发 pointerlockchage 或者 pointerlockerror 事件。
 */

/**
 * 扩展了 Document 接口 {
 *    attribute EventHandler onpointerlockchange;
 *    attribute EventHandler onpointerlockerror;
 *    void exitPointerLock();
 * }
 * exitPointerLock 方法：如果一个锁定目标元素的隐式根是当前document，且处于锁定状态，则初始化一个从锁定状态解除的流程。并触发 pointerlockchange 事件。
 */

/**
 * 与 DocumentOrShadowRoot 接口混合 {
 *    readyonly attribute Element ? pointerLockElement
 * }
 * pointerLockElement: 
 *    如果指针没有锁定或者锁定状态处于 pending 状态，则返回 null。如果指针已锁定，返回重新确定目标元素的结果，
 * 如果这个结果与上下文对象在同一树中，返回上下文对象，否则返回 null。
 */

/**
 * 货站 MouseEvent 接口 {
 *    readonly attribute long movementX;
 *    readonly attribute long movementY;
 * }
 *    这两个属性必须提供指针位置的改变，值与之后两个 mousemove 事件的事件对象 eNow 和 ePreviouse 有关，
 * 为 movementX = eNow.screenX - ePrevious.screenX，movementY同理。
 */

// 下面的示例展示了如何使用
const syntheticCursorInteraction = () => {
  let myCrusor = { x: 0, y: 0};

  document.addEventListener('mousemove', e => {
    myCrusor.x = e.clientX;
    myCrusor.y = e.clientY;
  })

  document.addEventListener('click', e => {
    if(e._isSynthetic) return;
    // 发送综合点击
    let ee = document.createEvent('MouseEvent');
    ee._isSynthetic = true;
    let x = myCrusor.x, y = myCrusor.y;
    ee.initMouseEvent('click', true, true, null, 1,
                      x + e.screenX - e.clientX,
                      y + e.screenY - e.clientY, x, y);
    let target = document.elementFromPoint(x, y);
    if(target) target.dispatchEvent(ee);
  })
}
syntheticCursorInteraction();